package com.example.graduationdesign.service.Impl;

import com.alibaba.fastjson2.JSONObject;
import com.example.graduationdesign.constant.Constant;
import com.example.graduationdesign.exception.CustomizeException;
import com.example.graduationdesign.mapper.CommonMapper;
import com.example.graduationdesign.mapper.ConsumerMapper;
import com.example.graduationdesign.pojo.dao.ArticleDao;
import com.example.graduationdesign.pojo.dao.ConsumerDao;
import com.example.graduationdesign.pojo.dao.RoleDao;
import com.example.graduationdesign.pojo.dao.UserDao;
import com.example.graduationdesign.pojo.dto.*;
import com.example.graduationdesign.pojo.vo.*;
import com.example.graduationdesign.service.CommonService;
import com.example.graduationdesign.utils.CommonUtil;
import com.example.graduationdesign.utils.EmailUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;


@Service
public class CommonServiceImpl implements CommonService {
    @Autowired
    private ConsumerMapper consumerMapper;
    @Autowired
    private CommonMapper commonMapper;

    @Autowired
    private JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String sender;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;


    /**
     * 用于实现用户登录操作
     * @param userLoginDto
     * @return
     */
    @Override
    public UserVo login(UserLoginDto userLoginDto) {
        UserDao userDao = commonMapper.queryUserByUserId(userLoginDto.getAccount());
        // 1. 验证用户登录账号是否存在 user_id
        if (!Optional.ofNullable(userDao).isPresent()) {
            throw new CustomizeException(ResultCode.USER_LOGIN_ERROR);
        }

        // 2. 账号存在，该用户是否活跃 is_active
        if (userDao.getIsActive() == 1) {
            throw new CustomizeException(ResultCode.USER_ACCOUNT_FORBIDDEN);
        }
        System.out.println(1);
        // 3. 判断 角色状态 是否可用
        // 3.1. 获取用户角色信息
        RoleDao roleDao = commonMapper.queryRoleByRoleId(userDao.getRoleId());

        // 3.2. 判断角色是否可用
        if (!Optional.ofNullable(roleDao).isPresent() || roleDao.getIsActive() == 1) {
            throw new CustomizeException(ResultCode.USER_ROLE_NOT_EXIST);
        }

        // 4. 该用户活跃，登录密码是否正确 password
        if (!DigestUtils.md5DigestAsHex(userLoginDto.getPassword().getBytes())
                .equals(userDao.getPassword())) {
            throw new CustomizeException(ResultCode.USER_LOGIN_ERROR);
        }

        // 5. 登录成功，封装用户相关信息
        UserVo userVo = new UserVo();

        // 5.1. 生成并封装 token
        String token = CommonUtil.generateToken(userDao.getUserId(), userDao.getUserName());
        userVo.setToken(token);

        //5.2 获取用户所处的阶段，用户类型以及用户得分情况
        ConsumerDao consumerVariety = commonMapper.queryConsdumerVarietyByConsumerId(userDao.getUserId());
        // 5.3. 封装 userVo 所需的基本信息
        userVo.setUserId(userDao.getUserId());
        userVo.setAvatar(userDao.getAvatar());
        userVo.setPhone(userDao.getPhone());
        userVo.setUserName(userDao.getUserName());
        userVo.setRoleId(roleDao.getRoleId());
        userVo.setRoleName(roleDao.getName());
        userVo.setPassword(userDao.getPassword());
        userVo.setConsumerStage(consumerVariety.getConsumerStage());
        userVo.setConsumerScore(consumerVariety.getConsumerScore());
        userVo.setConsumerVariety(consumerVariety.getConsumerVariety());
        userVo.setCurrentLevel(consumerVariety.getCurrentLevel());
        userVo.setSex(userDao.getSex());
        userVo.setAge(userDao.getAge());
        userVo.setEmail(userDao.getEmail());
        if (userDao.getRoleId().equals(100)) {
            userVo.setWordNumber((consumerMapper.queryWordByWordStage(consumerVariety.getConsumerStage())).size());
        }
        userVo.setPhone(userDao.getPhone());
        // 6. 将 userVo 缓存到 Redis
        redisTemplate.opsForValue().set(Constant.CLIENT_TOKEN + token, JSONObject.toJSONString(userVo), Constant.TOKEN_EXIST_TIME, TimeUnit.MINUTES);

        // 7. 返回结果
        return userVo;
    }

    /**
     * 发送邮箱邮件
     *
     * @param email
     * @return
     */
    @SneakyThrows
    @Override
    public String sendEmail(String email) {
        // 0. 判断该邮箱是否在数据库存在
        Long userId = commonMapper.getUserIdByEmail(email);
        if (!Optional.ofNullable(userId).isPresent()) {
            throw new CustomizeException(ResultCode.USER_EMAIL_NOT_EXIST);
        }

        // 1. 生成验证码
        String verificationCode = CommonUtil.generateVerificationCode(6);

        // 2. 给目标用户发送邮件
        // 2.1. 创建MINE邮件信息
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper mineHelper = new MimeMessageHelper(message, true);
        // 2.2. 完善邮件信息
        // 2.2.1. 编辑邮件
        EmailReceiver emailReceiver = new EmailReceiver();
        emailReceiver.setSubject("找回密码");
        EmailReceiver.Content content = emailReceiver.new Content();
        content.setExpirationTime(Constant.VERIFICATION_CODE_EXIST_TIME);
        content.setTitle("找回密码");
        content.setText("您的验证码");
        content.setCode(verificationCode);
        emailReceiver.setContent(content);
        // 2.2.2. 发送者
        mineHelper.setFrom(sender);
        // 2.2.3. 接收方
        mineHelper.setTo(email);
        // 2.2.4. 邮件标题
        mineHelper.setSubject(emailReceiver.getSubject());
        // 2.2.5. 邮件内容 true  表示邮件内容带有附件或html
        mineHelper.setText(EmailUtil.verificationCodeEmailFormat(emailReceiver), true);
        // 2.3. 发送邮件
        mailSender.send(message);

        // 3. 在Redis存储验证码，为了修改密码时验证用户发送的验证码是否合法
        // 3.1. 获取用户 token
        String token = CommonUtil.getCurrentUserToken();
        // 3.2. 存储数据
        redisTemplate.opsForValue().set(Constant.EMAIL_VERIFY + token, verificationCode, Constant.VERIFICATION_CODE_EXIST_TIME, TimeUnit.MINUTES);

        // 4. 返回验证码
        return verificationCode;
    }


    /**
     * 用于实现用户在注册时的邮箱验证
     * @param email
     * @return
     */
    @SneakyThrows
    @Override
    public String sendRegisterEmail(String email){

        // 1. 生成验证码
        String verificationCode = CommonUtil.generateVerificationCode(6);

        // 2. 给目标用户发送邮件
        // 2.1. 创建MINE邮件信息
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper mineHelper = new MimeMessageHelper(message, true);
        // 2.2. 完善邮件信息
        // 2.2.1. 编辑邮件
        EmailReceiver emailReceiver = new EmailReceiver();
        emailReceiver.setSubject("邮箱注册");
        EmailReceiver.Content content = emailReceiver.new Content();
        content.setExpirationTime(Constant.VERIFICATION_CODE_EXIST_TIME);
        content.setTitle("邮箱注册");
        content.setText("您的验证码");
        content.setCode(verificationCode);
        emailReceiver.setContent(content);
        // 2.2.2. 发送者
        mineHelper.setFrom(sender);
        // 2.2.3. 接收方
        mineHelper.setTo(email);
        // 2.2.4. 邮件标题
        mineHelper.setSubject(emailReceiver.getSubject());
        // 2.2.5. 邮件内容 true  表示邮件内容带有附件或html
        mineHelper.setText(EmailUtil.
                verificationCodeEmailFormatRegister(emailReceiver), true);
        // 2.3. 发送邮件
        mailSender.send(message);

        // 3. 在Redis存储验证码，为了修改密码时验证用户发送的验证码是否合法
        // 3.1. 获取用户 token
        String token = CommonUtil.getCurrentUserToken();
        // 3.2. 存储数据
        redisTemplate.opsForValue().set(
                Constant.EMAIL_VERIFY + token,
                verificationCode,
                Constant.VERIFICATION_CODE_EXIST_TIME,
                TimeUnit.MINUTES);

        // 4. 返回验证码
        return verificationCode;
    }


    /**
     * 用于实现用户在修改邮箱时发送验证码的功能
     * @param email
     * @return
     */
    @SneakyThrows
    @Override
    public String sendModifyEmail(String email,String newEmail) {
        // 0. 判断该邮箱是否在数据库存在
        Long userId = commonMapper.getUserIdByEmail(email);
        if (!Optional.ofNullable(userId).isPresent()) {
            throw new CustomizeException(ResultCode.USER_EMAIL_NOT_EXIST);
        }

        // 1. 生成验证码
        String verificationCode = CommonUtil.generateVerificationCode(6);
        System.out.println(verificationCode);

        // 2. 给目标用户发送邮件
        // 2.1. 创建MINE邮件信息
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper mineHelper = new MimeMessageHelper(message, true);
        // 2.2. 完善邮件信息
        // 2.2.1. 编辑邮件
        EmailReceiver emailReceiver = new EmailReceiver();
        emailReceiver.setSubject("邮箱修改");
        EmailReceiver.Content content = emailReceiver.new Content();
        content.setExpirationTime(Constant.VERIFICATION_CODE_EXIST_TIME);
        content.setTitle("邮箱修改");
        content.setText("您的验证码");
        content.setCode(verificationCode);
        emailReceiver.setContent(content);
        // 2.2.2. 发送者
        mineHelper.setFrom(sender);
        // 2.2.3. 接收方
        mineHelper.setTo(newEmail);
        // 2.2.4. 邮件标题
        mineHelper.setSubject(emailReceiver.getSubject());
        // 2.2.5. 邮件内容 true  表示邮件内容带有附件或html
        mineHelper.setText(EmailUtil.verificationCodeEmailFormatModifyEmail(emailReceiver), true);
        // 2.3. 发送邮件
        mailSender.send(message);

        // 3. 在Redis存储验证码，为了修改密码时验证用户发送的验证码是否合法
        // 3.1. 获取用户 token
        String token = CommonUtil.getCurrentUserToken();
        // 3.2. 存储数据
        redisTemplate.opsForValue().set(Constant.EMAIL_VERIFY + token, verificationCode, Constant.VERIFICATION_CODE_EXIST_TIME, TimeUnit.MINUTES);

        // 4. 返回验证码
        return verificationCode;
    }

    /**
     * 忘记密码
     *
     * @param forgetPwdDto
     */
    @Override
    @Transactional
    public void forgetPassword(ForgetPwdDto forgetPwdDto) {
        // 1. 判断该邮箱是否在数据库存在
        Long userId = commonMapper.getUserIdByEmail(forgetPwdDto.getEmail());
        if (!Optional.ofNullable(userId).isPresent()) {
            throw new CustomizeException(ResultCode.USER_EMAIL_NOT_EXIST);
        }

        // 2. 在Redis中取出验证码，和发送请求验证码比对
        // 2.1. 获取 token
        String token = CommonUtil.getCurrentUserToken();

        // 2.2. 获取 Redis 里面的目标验证码
        String verificationCode = (String) redisTemplate.opsForValue().get(Constant.EMAIL_VERIFY + token);
        if (!Optional.ofNullable(verificationCode).isPresent()) {
            throw new CustomizeException(ResultCode.VERIFICATION_CODE);
        }
        // 2.3. 比较验证码
        if (!verificationCode.equals(forgetPwdDto.getVerificationCode())) {
            throw new CustomizeException(ResultCode.VERIFICATION_CODE);
        }


        // 3. 成功之后，修改用户密码
        commonMapper.modifyUserPasswordByUserId(forgetPwdDto.getPassword(), userId);
    }


    /**
     * 用于实现用户注册功能的Service层的实现层
     * @param registerDto
     */
    @Override
    public Long RegisterView(RegisterDto registerDto) {
        // 2. 在Redis中取出验证码，和发送请求验证码比对
        // 2.1. 获取 token
        String token = CommonUtil.getCurrentUserToken();

        // 2.2. 获取 Redis 里面的目标验证码
        String verificationCode = (String) redisTemplate.opsForValue().get(Constant.EMAIL_VERIFY + token);
        if (!Optional.ofNullable(verificationCode).isPresent()) {
            throw new CustomizeException(ResultCode.VERIFICATION_CODE);
        }
        // 2.3. 比较验证码
        if (!verificationCode.equals(registerDto.getVerificationCode())) {
            throw new CustomizeException(ResultCode.VERIFICATION_CODE);
        }
        commonMapper.InsertUser(registerDto);
        commonMapper.InsertConsumer(commonMapper.GetConsumerId(registerDto.getEmail()));
        UserDao userDao1 = commonMapper.GetUserId();
        return userDao1.getUserId();
    }


    /**
     * 用户退出系统
     */
    @Override
    public void logout() {
        // 1. 获取当前用户请求头中的 token
        String token = CommonUtil.getCurrentUserToken();
        System.out.println(token);

        // 2. 删除 Redis 中保存用户登录信息
        Boolean delete = redisTemplate.delete(Constant.CLIENT_TOKEN + token);
        if (Boolean.FALSE.equals(delete)) {
            throw new CustomizeException(ResultCode.SYSTEM_INNER_ERROR);
        }
    }


    /*
     * 用于实现上传图片即修改头像的功能并将数据写入数据库
     * */

    @Override
    public String uploadPicture(String picturePath,Long userId) {
        // 在Redis中取出当前用户的Id，用于找到当前教练所教的学员的基本信息
        // 获取 token,从而得到当前登录用户的基本信息
//        String token = CommonUtil.getCurrentUserToken();
//        UserVo userVo = JSONObject.parseObject(String.valueOf(redisTemplate.opsForValue().get(Constant.CLIENT_TOKEN + token)), UserVo.class);

        /*
         * 使用coachMapper实现对数据库的处理
         *
         * */

        commonMapper.UpdateAvatarById(picturePath, userId);
        return picturePath;
    }

    /**
     * 用于客户端用户的数据更新操作
     * @param userVo
     * @return
     */
    @Override
    public Void UpdateUserInfomation(UserVo userVo) {
        commonMapper.UpdateUserInfomation(userVo);
        commonMapper.UpdateStage(userVo);
        return null;
    }

    /**
     * 用于用户修改邮箱的操作
     * @param modifyEmailDto
     * @return
     */
    @Override
    public Void UpdateUserEmailInfomation(ModifyEmailDto modifyEmailDto) {
        System.out.println("q2w133333333333");
        System.out.println(modifyEmailDto);
        // 2. 在Redis中取出验证码，和发送请求验证码比对
        // 2.1. 获取 token
        String token = CommonUtil.getCurrentUserToken();

        // 2.2. 获取 Redis 里面的目标验证码
        String verificationCode = (String) redisTemplate.opsForValue().get(Constant.EMAIL_VERIFY + token);
        System.out.println(verificationCode);
        if (!Optional.ofNullable(verificationCode).isPresent()) {
            throw new CustomizeException(ResultCode.VERIFICATION_CODE);
        }
        // 2.3. 比较验证码
        if (!verificationCode.equals(modifyEmailDto.getVerificationCode())) {
            throw new CustomizeException(ResultCode.VERIFICATION_CODE);
        }
        commonMapper.UpdateUserEmailInfomation(modifyEmailDto);
        return null;
    }

    /**
     * 实现管理员用户的信息修改
     * @param userVo
     * @return
     */
    @Override
    public Void UpdateAdminInfomation(UserVo userVo) {
        commonMapper.UpdateAdminInfomation(userVo);
        return null;
    }

    /**
     * 用于获取文章信息
     * @return
     */
    @Override
    public List<ArticleDao> GetArticle() {
        List<ArticleDao> articleDaos= new ArrayList<>();
        articleDaos = commonMapper.GetArticle();
        return articleDaos;
    }

    /**
     * 用于实现获取用户地理位置的功能
     * @param userId
     * @param city
     * @return
     */
    @Override
    public Void UpdateCity(Long userId, String city) {
        commonMapper.UpdateCity(userId,city);
        return null;
    }

    /**
     * 用于实现获取用户的
     * @param email
     * @return
     */
    @Override
    public Long GetAccount(String email) {
        Long data = commonMapper.GetAccount(email);
        return data;
    }

    @Override
    public DataList GetData(String startDate, String endDate) {

        List<Yuding> yudings = commonMapper.getYuding(startDate,endDate);
        List<Jingdian> jingdians = commonMapper.getJingdian();
        DataList dataList = new DataList();
        dataList.setJingdianData(jingdians);
        dataList.setYudingData(yudings);
        return dataList;
    }

    @Override
    public List<Jingdian> GetJingdianData() {
        List<Jingdian> jingdians = commonMapper.getJingdian();
        return jingdians;
    }
}
